﻿using System;
using System.Collections.Specialized;
using System.Configuration;
using System.Linq;
using System.Reflection;
using Ninject;
using Ninject.Activation;
using Ninject.Planning;
using Ninject.Planning.Directives;
using Ninject.Selection.Heuristics;

namespace ninject.configurer
{
    public class ConfigSectionProvider : BaseConfigurationProvider
    {
        private readonly string _sectionName;

        public ConfigSectionProvider(string sectionName, Type type, IPlanner planner, IConstructorScorer scorer)
            : base(type, planner, scorer)
        {
            _sectionName = sectionName;
        }

        public override object Create(IContext context)
        {
            if (context.Plan == null)
                context.Plan = Planner.GetPlan(Type);

            ConstructorInjectionDirective directive =
                (from option in context.Plan.GetAll<ConstructorInjectionDirective>()
                 orderby ConfigurationScorer(context, option) descending
                 select option).First();

            object sectionObj = ConfigurationManager.GetSection(_sectionName);

            object[] arguments =
                (from target in directive.Targets select GetValue(sectionObj, target.Name)).ToArray();

            return directive.Injector(arguments);
        }

        public object GetValue(object sectionObj, string targetName)
        {
            var nameValueSection = sectionObj as NameValueCollection;

            if (nameValueSection != null)
                return nameValueSection[targetName];

            PropertyInfo propInfo = sectionObj.GetType().GetProperties()
                .Where(p => String.Compare(p.Name, targetName, true) == 0)
                .Single();

            if (propInfo == null)
                throw new ActivationException(
                    String.Format("Property {0} not found in configuration section {1}", targetName, _sectionName));

            return propInfo.GetValue(sectionObj, null);
        }
    }
}